package org.piggy.gateway;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class HttpServerMax {

    private final static Logger logger = LoggerFactory.getLogger(HttpServerMax.class);

    public static void main(String[] args) throws InterruptedException, IOException {
        EventLoopGroup boss = new NioEventLoopGroup(1);
        EventLoopGroup work = new NioEventLoopGroup(4);
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, work)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel channel) {

                        ChannelPipeline pipeline = channel.pipeline();
                        pipeline.addLast(new HttpServerCodec());
                        pipeline.addLast(new HttpObjectAggregator(65536));

                        pipeline.addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                logger.info("channelInactive.channel.hashcode -> {}", ctx.channel().hashCode());
                                ctx.close();
                            }

                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                logger.info("channelActive.channel.hashcode -> {}", ctx.channel().hashCode());
                                ChannelFuture channelFuture = HttpClient.getChannelFuture();
                                Channel connect = channelFuture.channel();
                                ctx.channel().attr(AttributeKey.valueOf(HttpClient.attr)).set(connect);
                                connect.attr(AttributeKey.valueOf(HttpClient.attr)).set(ctx.channel());
                            }

                            @Override
                            public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
                                super.channelRegistered(ctx);
                            }

                            @Override
                            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                ctx.close();
                                cause.printStackTrace();
                            }

                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) {
                                if (msg instanceof FullHttpRequest) {
                                    logger.info("channelRead.channel.hashcode -> {}", ctx.channel().hashCode());
                                    FullHttpRequest request = (FullHttpRequest) msg;
                                    String connection = request.headers().get(HttpHeaderNames.CONNECTION);
                                    String upgrade = request.headers().get(HttpHeaderNames.UPGRADE);
                                    if (upgrade == null) {
                                        // http
                                        if( "keep-alive".equals(connection)){
                                            Object o = ctx.channel().attr(AttributeKey.valueOf(HttpClient.attr)).get();
                                            Channel channel = (Channel) o;
                                            channel.writeAndFlush(request);
                                        }
                                    }
                                }
                            }
                        });
                    }
                });

        Channel channel = bootstrap.bind(Config.getConfigParam().getIp(), Config.getConfigParam().getPort()).sync().channel();
        ChannelFuture channelFuture = channel.closeFuture().sync();
        channelFuture.addListener((ChannelFutureListener) listener -> logger.info("server close"));
    }
}
